package com.logic.service.impl;

import java.io.Serializable;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.inject.Named;

import org.primefaces.model.chart.Axis;
import org.primefaces.model.chart.AxisType;
import org.primefaces.model.chart.BarChartModel;
import org.primefaces.model.chart.BarChartSeries;
import org.primefaces.model.chart.BubbleChartModel;
import org.primefaces.model.chart.BubbleChartSeries;
import org.primefaces.model.chart.CategoryAxis;
import org.primefaces.model.chart.ChartSeries;
import org.primefaces.model.chart.LineChartModel;
import org.primefaces.model.chart.LineChartSeries;
import org.primefaces.model.chart.LinearAxis;
import org.primefaces.model.chart.PieChartModel;

import com.constants.Constants;
import com.database.bean.CompanyProduct;
import com.database.bean.Game;
import com.database.bean.Product;
import com.database.bean.Report;
import com.database.bean.Round;
import com.database.bean.User;
import com.logic.service.CompanyService;
import com.math.util.StatisticBean;

@Named
public class CompanyServiceImpl extends BaseServiceImpl implements Serializable, CompanyService {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;

	@Override
	public List<Product> getAllProducts() {
		List<Product> allProducts= this.productDao.getAll();
		
		if (allProducts != null) {
			logger.debug("Returned all Products:" + allProducts.size());
		}
		return allProducts;
	}
	
	@Override
	public List<Product> getAllActiveProducts() {
		List<Product> allProducts= this.productDao.getAllActive();
		
		if (allProducts != null) {
			logger.debug("Returned all Products:" + allProducts.size());
		}
		return allProducts;
	}
	
	@Override
	public List<Report> getAllReports() {
		List<Report> allReports= this.reportDao.getAll();
		
		if (allReports != null) {
			logger.debug("Returned all Reports:" + allReports.size());
		}
		return allReports;
	}
	
	@Override
	public List<CompanyProduct> getAllCompanyProducts() {
		List<CompanyProduct> allCompanyProduct= this.companyProductDao.getAll();
		
		if (allCompanyProduct != null) {
			logger.debug("Returned all CompanyProduct:" + allCompanyProduct.size());
		}
		return allCompanyProduct;
	}
	
	@Override
	public PieChartModel getMarketLastRoundSellingsPie(Game game, Round deadlineRound){
		PieChartModel model = new PieChartModel();
		String title=null;
		List<StatisticBean> results=statisticDao.getMarketLastRoundSellings(game, deadlineRound);
		
		if (results.size() > 0) {
			for (StatisticBean result : results) {
				title = result.getCompany_nickname() + "("
						+ result.getCompprod_amountSold() + ")";
				model.set(title, result.getCompprod_amountSold());
			}

			model.setTitle("Sellings");
			model.setLegendPosition("w");
			model.setShowDataLabels(true);
			model.setDataFormat("label");
		} else {
			model = null;
		}
				
		return model;
	}
	
	@Override
	public BubbleChartModel getMarketLastRoundsProductsBubble(Game game, Round deadlineRound){
		BubbleChartModel model = new BubbleChartModel();

		List<StatisticBean> results=statisticDao.getMarketLastRoundsProducts(game, deadlineRound);
		
		for(StatisticBean result : results){	   
			Double quality = result.getProduct_qualityFactor()*10;
			int qual =(int) Math.round(quality);
			if(result.getCompprod_amountSold()!=null && result.getCompprod_amountSold().intValue()>0){
				model.add(new BubbleChartSeries(result.getProduct_name(), result.getCompprod_sellingPrice().intValue(), qual, result.getCompprod_amountSold().intValue()));
			}
		}
		
		model.setTitle("Sold Products");
        model.getAxis(AxisType.X).setLabel("Price");
        Axis yAxis = model.getAxis(AxisType.Y);
        yAxis.setMin(0);
        yAxis.setMax(10);
        yAxis.setLabel("Quality");
				
		return model;
	}
	
	@Override
	public BarChartModel getMarketGameProductSellings(Game game, Round deadlineRound){
		BarChartModel model = new BarChartModel();
		
		List<StatisticBean> data = this.statisticDao.getMarketGameProductSellings(game, deadlineRound);
		
		ChartSeries products = new ChartSeries();
		products.setLabel("Products");
		
		for(StatisticBean sbean:data){
			if(sbean.getCompprod_amountSold()!=null && sbean.getCompprod_amountSold().intValue()>0){
				products.set(sbean.getProduct_name(), sbean.getCompprod_amountSold());
			}
        }
		
		model.addSeries(products);
		model.setTitle("Market Product Sellings");
		model.setLegendPosition("ne");
		Axis xAxis = model.getAxis(AxisType.X);
		xAxis.setLabel("Products");
		Axis yAxis = model.getAxis(AxisType.Y);
		yAxis.setLabel("Sellings");
		yAxis.setMin(0);
		//yAxis.setMax(200);
		
		return model;
	}
	
	@Override
	public BarChartModel getMarketGameCompanySellingsPerRound(Game game, Round deadlineRound){
		BarChartModel model = new BarChartModel();
		
		List<StatisticBean> data = this.statisticDao.getMarketGameCompanySellingsPerRound(game, deadlineRound);
		
		ChartSeries series = new ChartSeries();
		series.setLabel("Products");
		
		for(StatisticBean sbean:data){
			series.set(sbean.getCompany_nickname()+"-"+sbean.getRound_number(), sbean.getCompprod_amountSold());
        }
		
		model.addSeries(series);
		model.setTitle("Market Game Company Sellings Per Round");
		model.setLegendPosition("ne");
		Axis xAxis = model.getAxis(AxisType.X);
		xAxis.setLabel("Companies-Round");
		Axis yAxis = model.getAxis(AxisType.Y);
		yAxis.setLabel("Sellings");
		yAxis.setMin(0);
		//yAxis.setMax(200);
		
		return model;
	}
	
	@Override
	public LineChartModel getMarketGameCompanySellingsPerRoundLineChart(Game game, Round deadlineRound) {
		List<StatisticBean> results=this.statisticDao.getMarketGameCompanySellingsPerRound(game, deadlineRound);
		LineChartModel model = new LineChartModel();
		Map<String,ChartSeries> map=new HashMap<String,ChartSeries>();
		
		for(StatisticBean result : results){
			if(map.containsKey(result.getCompany_nickname())){
				ChartSeries firm=map.get(result.getCompany_nickname());
				firm.set("Round "+result.getRound_number(), result.getCompprod_amountSold());
				map.put(result.getCompany_nickname(), firm);
			}else{
				ChartSeries firm = new ChartSeries();
				firm.setLabel(result.getCompany_nickname());
				firm.set("Round "+result.getRound_number(), result.getCompprod_amountSold());
		        map.put(result.getCompany_nickname(), firm);
			}
		}
		
		for(ChartSeries firm : map.values()){
			model.addSeries(firm);
		}
		
		model.setTitle("Market Game Company Sellings Per Round");
		model.setLegendPosition("e");
		model.setShowPointLabels(true);
		model.getAxes().put(AxisType.X, new CategoryAxis("Rounds"));
		Axis yAxis = model.getAxis(AxisType.Y);
	    yAxis.setLabel("Number of sold products");
        //Axis yAxis = model.getAxis(AxisType.Y);
        //yAxis.setMin(0);
        //yAxis.setMax(10);
		
		return model;
	}
	
	@Override
	public BarChartModel getMarketGameCompanySellings(Game game, Round deadlineRound){
		BarChartModel model = new BarChartModel();
		
		List<StatisticBean> data = this.statisticDao.getMarketGameCompanySellings(game, deadlineRound);
		
		ChartSeries series = new ChartSeries();
		series.setLabel("Products");
		
		for(StatisticBean sbean:data){
			series.set(sbean.getCompany_nickname(), sbean.getCompprod_amountSold());
        }
		
		model.addSeries(series);
		model.setTitle("Market Game Company Sellings");
		model.setLegendPosition("ne");
		Axis xAxis = model.getAxis(AxisType.X);
		xAxis.setLabel("Companies");
		Axis yAxis = model.getAxis(AxisType.Y);
		yAxis.setLabel("Sellings");
		yAxis.setMin(0);
		//yAxis.setMax(200);
		
		return model;
	}
	
	@Override
	public BarChartModel getMarketGameAgentImage(Game game, Round deadlineRound){
		BarChartModel model = new BarChartModel();
		
		List<StatisticBean> data = this.statisticDao.getMarketGameAgentImage(game, deadlineRound);
		
		ChartSeries series = new ChartSeries();
		series = this.getPrefRegions(data, "Image");
		series.setLabel("Number of agents");
		
		model.addSeries(series);
		model.setTitle("Agent Preference Image");
		model.setLegendPosition("ne");
		Axis xAxis = model.getAxis(AxisType.X);
		xAxis.setLabel("Image Scope");
		Axis yAxis = model.getAxis(AxisType.Y);
		yAxis.setLabel("Number of agents");
		yAxis.setMin(0);
		//yAxis.setMax(200);
		
		return model;
	}
	
	/**
	 * 
	 * @param data
	 * @param pref
	 * @return
	 */
	private ChartSeries getPrefRegions(List<StatisticBean> data, String pref){
		ChartSeries series = new ChartSeries();
		int reg02=0;
		int reg35=0;
		int reg68=0;
		int reg910=0;
		
		for (StatisticBean sbean : data) {
			int preference=0;
			if("Quality".equals(pref)){
				preference=sbean.getAgent_preferenceQuality().intValue();
			}else if("Price".equals(pref)){
				preference=sbean.getAgent_preferencePrice().intValue();
			}else{
				preference=sbean.getAgent_preferenceImage().intValue();
			}
			switch (preference) {
			case 0:
			case 1:
			case 2:
				reg02 += sbean.getCount().intValue();
				break;
			case 3:
			case 4:
			case 5:
				reg35 += sbean.getCount().intValue();
				break;
			case 6:
			case 7:
			case 8:
				reg68 += sbean.getCount().intValue();
				break;
			case 9:
			case 10:
				reg910 += sbean.getCount().intValue();
				break;
			}
		}
		
		series.set("0-2", reg02);
		series.set("3-5", reg35);
		series.set("6-8", reg68);
		series.set("9-10", reg910);
		
		return series;
	}
	
	@Override
	public BarChartModel getMarketGameAgentPrice(Game game, Round deadlineRound){
		BarChartModel model = new BarChartModel();
		
		List<StatisticBean> data = this.statisticDao.getMarketGameAgentPrice(game, deadlineRound);
		
		ChartSeries series = new ChartSeries();
		series = this.getPrefRegions(data, "Price");
		series.setLabel("Number of agents");
		
		/*
		for(StatisticBean sbean:data){
        	products.set(this.getRegion(sbean.getAgent_preferencePrice()), sbean.getCount());
        }
        */
		
		model.addSeries(series);
		model.setTitle("Agent Preference Price");
		model.setLegendPosition("ne");
		Axis xAxis = model.getAxis(AxisType.X);
		xAxis.setLabel("Price Scope");
		Axis yAxis = model.getAxis(AxisType.Y);
		yAxis.setLabel("Number of agents");
		yAxis.setMin(0);
		//yAxis.setMax(200);
		
		return model;
	}
	
	@Override
	public BarChartModel getMarketGameAgentQuality(Game game, Round deadlineRound){
		BarChartModel model = new BarChartModel();
		
		List<StatisticBean> data = this.statisticDao.getMarketGameAgentQuality(game, deadlineRound);
		
		ChartSeries series = new ChartSeries();
		series = this.getPrefRegions(data, "Quality");
		series.setLabel("Number of agents");
		
		model.addSeries(series);
		model.setTitle("Agent Preference Quality");
		model.setLegendPosition("ne");
		Axis xAxis = model.getAxis(AxisType.X);
		xAxis.setLabel("Quality Scope");
		Axis yAxis = model.getAxis(AxisType.Y);
		yAxis.setLabel("Number of agents");
		yAxis.setMin(0);
		//yAxis.setMax(200);
		
		return model;
	}

	
	@Override
	public LineChartModel getCompanyGameMarketingInvestments(User company) {
		LineChartModel multiAxisModel = new LineChartModel();
 
		List<StatisticBean> data = this.statisticDao.getCompanyGameInvestments(company);
		
        BarChartSeries bars = new BarChartSeries();
        bars.setLabel(Constants.CHART_HEADER_MARKETING_INV);
        LineChartSeries lines = new LineChartSeries();
        lines.setLabel(Constants.CHART_HEADER_MARKETING_INV);
 
        for(StatisticBean sbean:data){
        	bars.set(sbean.getRound_number(), sbean.getDecres_marketingInvestment());
        	lines.set(sbean.getRound_number(), sbean.getDecres_marketingInvestment());
        }
        
        lines.setXaxis(AxisType.X2);
        lines.setYaxis(AxisType.Y2);
        
        multiAxisModel.addSeries(bars);
        multiAxisModel.addSeries(lines);
         
        multiAxisModel.setTitle(Constants.CHART_HEADER_MARKETING_INV);
        multiAxisModel.setMouseoverHighlight(false);
         
        multiAxisModel.getAxes().put(AxisType.X, new CategoryAxis(Constants.CHART_AXIS_ROUND));
        multiAxisModel.getAxes().put(AxisType.X2, new CategoryAxis(Constants.CHART_AXIS_ROUND2));
         
        Axis yAxis = multiAxisModel.getAxis(AxisType.Y);
        yAxis.setLabel(Constants.CHART_AXIS_INVESTMENT);
        yAxis.setMin(0);
                 
        Axis y2Axis = new LinearAxis(Constants.CHART_AXIS_INVESTMENT2);
        y2Axis.setMin(0); 
        multiAxisModel.getAxes().put(AxisType.Y2, y2Axis);
        
        
        return multiAxisModel;
    }

	@Override
	public LineChartModel getCompanyGameEmployerInvestments(User company) {
		LineChartModel multiAxisModel = new LineChartModel();
 
		List<StatisticBean> data = this.statisticDao.getCompanyGameInvestments(company);
		
        BarChartSeries bars = new BarChartSeries();
        bars.setLabel(Constants.CHART_HEADER_PERSONAL_INV);
        LineChartSeries lines = new LineChartSeries();
        lines.setLabel(Constants.CHART_HEADER_PERSONAL_INV);
 
        for(StatisticBean sbean:data){
        	bars.set(sbean.getRound_number(), sbean.getDecres_employerEducationInvestment());
        	lines.set(sbean.getRound_number(), sbean.getDecres_employerEducationInvestment());
        }
        
        lines.setXaxis(AxisType.X2);
        lines.setYaxis(AxisType.Y2);
        
        multiAxisModel.addSeries(bars);
        multiAxisModel.addSeries(lines);
         
        multiAxisModel.setTitle(Constants.CHART_HEADER_PERSONAL_INV);
        multiAxisModel.setMouseoverHighlight(false);
         
        multiAxisModel.getAxes().put(AxisType.X, new CategoryAxis(Constants.CHART_AXIS_ROUND));
        multiAxisModel.getAxes().put(AxisType.X2, new CategoryAxis(Constants.CHART_AXIS_ROUND2));
         
        Axis yAxis = multiAxisModel.getAxis(AxisType.Y);
        yAxis.setLabel(Constants.CHART_AXIS_INVESTMENT);
        yAxis.setMin(0);
                 
        Axis y2Axis = new LinearAxis(Constants.CHART_AXIS_INVESTMENT2);
        y2Axis.setMin(0);
         
        multiAxisModel.getAxes().put(AxisType.Y2, y2Axis);
        
        return multiAxisModel;
    }
	
	@Override
	public LineChartModel getCompanyGameRDInvestments(User company) {
		LineChartModel multiAxisModel = new LineChartModel();
 
		List<StatisticBean> data = this.statisticDao.getCompanyGameInvestments(company);
		
        BarChartSeries bars = new BarChartSeries();
        bars.setLabel(Constants.CHART_HEADER_RD_INV);
        LineChartSeries lines = new LineChartSeries();
        lines.setLabel(Constants.CHART_HEADER_RD_INV);
 
        for(StatisticBean sbean:data){
        	bars.set(sbean.getRound_number(), sbean.getDecres_rdInvestment());
        	lines.set(sbean.getRound_number(), sbean.getDecres_rdInvestment());
        }
        
        lines.setXaxis(AxisType.X2);
        lines.setYaxis(AxisType.Y2);
        
        multiAxisModel.addSeries(bars);
        multiAxisModel.addSeries(lines);
         
        multiAxisModel.setTitle(Constants.CHART_HEADER_RD_INV);
        multiAxisModel.setMouseoverHighlight(false);
         
        multiAxisModel.getAxes().put(AxisType.X, new CategoryAxis(Constants.CHART_AXIS_ROUND));
        multiAxisModel.getAxes().put(AxisType.X2, new CategoryAxis(Constants.CHART_AXIS_ROUND2));
         
        Axis yAxis = multiAxisModel.getAxis(AxisType.Y);
        yAxis.setLabel(Constants.CHART_AXIS_INVESTMENT);
        yAxis.setMin(0);
                 
        Axis y2Axis = new LinearAxis(Constants.CHART_AXIS_INVESTMENT2);
        y2Axis.setMin(0);
         
        multiAxisModel.getAxes().put(AxisType.Y2, y2Axis);
        
        return multiAxisModel;
    }
	
	@Override
	public List<StatisticBean> getCompanyGameDecisions(User competitor, Round deadlineRound, boolean exactRound) {
		return this.statisticDao.getCompanyGameDecisions(competitor, deadlineRound, exactRound);
	}
	
	@Override
	public List<StatisticBean> getCompanyGameCompanyProducts(User competitor, Round deadlineRound, boolean exactRound) {
		return this.statisticDao.getCompanyGameCompanyProducts(competitor, deadlineRound, exactRound);
	}
	
	@Override
	public List<StatisticBean> getMarketGameCompanyProducts(Game game, Round deadlineRound) {
		return this.statisticDao.getMarketGameCompanyProducts(game, deadlineRound);
	}
	
	@Override
	public List<StatisticBean> getMarketGameDecisionsDeadline(Round deadlineRound){
		return this.statisticDao.getMarketGameDecisionsDeadline(deadlineRound);
	}
	
	@Override
	public List<StatisticBean> getMarketGameDecisionsDeadlinePercentage(Round deadlineRound, double percentage, User company){
		return this.statisticDao.getMarketGameDecisionsDeadlinePercentage(deadlineRound,percentage,company);
	}
	
	@Override
	public List<StatisticBean> getMarketGameSummedUpDecisionsDeadline(Round deadlineRound) {
		return this.statisticDao.getMarketGameSummedUpDecisionsDeadline(deadlineRound);
	}
	
	@Override
	public List<StatisticBean> getMarketGameAgentPercentage(Round round, double percentage){
		return this.statisticDao.getMarketGameAgentPercentage(round, percentage);
	}
	
	@Override
	public List<StatisticBean> getMarketGameAgentPreferencesPercentage(Round round, double percentage){
		return this.statisticDao.getMarketGameAgentPreferencesPercentage(round, percentage);
	}
	
	@Override
	public Integer getMarketGameAgentAmount(Game game, Round deadlineRound){
		return this.statisticDao.getMarketGameAgentAmount(game, deadlineRound);
	}
	
	/**
	 * Returns the amount of different values before/equal deadlineRound
	 * @param deadlineRound
	 * @author Patrick
	 * @return
	 */
	public List<StatisticBean> getMarketGameAmounts(Round deadlineRound) {
		return this.statisticDao.getMarketGameAmounts(deadlineRound);
	}

}